package zhoug.player.hikvision;

import android.text.TextUtils;
import android.util.Log;
import android.view.TextureView;


import com.hikvision.hatomplayer.DefaultHatomPlayer;
import com.hikvision.hatomplayer.HatomPlayer;
import com.hikvision.hatomplayer.PlayCallback;
import com.hikvision.hatomplayer.PlayConfig;

import java.util.Locale;
import java.util.Map;
import java.util.Objects;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import zhoug.common.utils.ThreadUtils;
import zhoug.logging.Logger;
import zhoug.player.core.OnCapturePictureListener;
import zhoug.player.core.OnPlayListener;
import zhoug.player.core.OnPlayProgressListener;
import zhoug.player.core.OnTalkListener;
import zhoug.player.core.OnVideoRecordListener;
import zhoug.player.core.PlayError;
import zhoug.player.core.PlayerSDK2;
import zhoug.player.core.ZPlayer;

import static zhoug.player.core.ZPlayer.STATE_IDLE;
import static zhoug.player.core.ZPlayer.STATE_PAUSE;
import static zhoug.player.core.ZPlayer.STATE_PLAYING;
import static zhoug.player.core.ZPlayer.STATE_START;


/**
 * 还好播放器封装
 *
 * @Author: zhoug
 * @Date: 2023/9/12
 * @Description:
 */
public class HikPlayer {
    private static final boolean DEBUG= PlayerSDK2.isDebug();
    private static final String TAG = ">>>HikPlayer";
    private HikPlayConfig mHikPlayConfig;
    private HatomPlayer mPlayer;
    private final PlayConfig mPlayConfig = new PlayConfig();
    private String mPlayUrl;//播放地址
    private String mTalkUrl;//对讲地址
    /**
     * 回放需要设置开始时间{@link HeaderParams#START_TIME}和结束时间{@link HeaderParams#END_TIME}
     * 时间格式为 "yyyy-MM-dd'T'HH:mm:ss.SSSZ
     * key {@link HeaderParams}
     */
    private Map<String, String> mPlayHeaderMap;//播放Header参数
    /**
     *
     * key {@link HeaderParams}
     */
    private Map<String, String> mTalkHeaderMap;//对讲Header参数

    private TextureView mTextureView;
    private @ZPlayer.State int mState = STATE_IDLE;//播放状态
    private boolean mTalking=false;//是否正在对讲
    private boolean mMute=true;//默认静音
    private OnPlayListener mPlayListener;//播放监听
    private OnCapturePictureListener mCapturePictureListener;//截图监听
    private OnVideoRecordListener mVideoRecordListener;//录像监听
    private OnPlayProgressListener mPlayProgressListener;//播放进度监听
    private OnTalkListener mOnTalkListener;//对讲监听

    public HikPlayer() {

    }

    public HikPlayer(HikPlayConfig hikPlayConfig) {
        this.mHikPlayConfig = hikPlayConfig;
    }

    /**
     * 播放状态回掉
     */
    private final PlayCallback.PlayStatusCallback mPlayStatusCallback = new PlayCallback.PlayStatusCallback() {
        @Override
        public void onPlayerStatus(@NonNull PlayCallback.Status status, String errorCode) {
            //status 共三种状态：SUCCESS（播放成功）、FAILED（播放失败）、EXCEPTION（取流异常）
            //错误码，只有 FAILED 和 EXCEPTION 才有值
            //注意：回调仍为子线程
            String errorMsg = null;
            int code = PlayError.UNKNOWN_ERROR;
            if (!TextUtils.isEmpty(errorCode)) {
                errorCode = HikErrors.errorCodeToHexString(errorCode);
                errorMsg = HikErrors.getErrorMsg(errorCode);
                if (Objects.equals(HikErrors.URL_EXPIRE, errorCode)) {
                    code = PlayError.URL_EXPIRE;
                }
            }
            switch (status) {
                case SUCCESS:
                    if (DEBUG) {
                        Logger.d(TAG, "onPlayerStatus:播放成功");
                    }
                    callStatusChange(STATE_PLAYING);
                    break;
                case FAILED:
                    Logger.e(TAG, "onPlayerStatus:播放失败:" + errorMsg);
                    stopPlay();
                    callError(code, errorMsg);
                    break;
                case FINISH:
                    if (DEBUG) {
                        Logger.d(TAG, "onPlayerStatus:播放完成");
                    }
                    stopPlay();
                    break;
                case EXCEPTION:
                    Logger.e(TAG, "onPlayerStatus:取流异常:" + errorMsg);
                    stopPlay();
                    callError(PlayError.IO_EXCEPTION, errorMsg);
                    break;
            }

        }
    };

    /**
     * 语音对讲回掉
     */
    private final PlayCallback.VoiceTalkCallback mVoiceTalkCallback = new PlayCallback.VoiceTalkCallback() {
        @Override
        public void onTalkStatus(@NonNull PlayCallback.Status status, String errorCode) {
            //status 共三种状态：SUCCESS（播放成功）、FAILED（播放失败）、EXCEPTION（取流异常）
            //错误码，只有 FAILED 和 EXCEPTION 才有值
            //注意：回调仍为子线程
            String errorMsg = null;
            if (!TextUtils.isEmpty(errorCode)) {
                errorCode = HikErrors.errorCodeToHexString(errorCode);
                errorMsg = HikErrors.getErrorMsg(errorCode);
            }
            switch (status) {
                case SUCCESS:
                    mTalking=true;
                    if (DEBUG) {
                        Logger.d(TAG, "onTalkStatus:对讲成功");
                    }
                    callTalkListener(OnTalkListener.SUCCESS, null);
                    break;
                case FAILED:
                    mTalking=false;
                    Logger.e(TAG, "onTalkStatus:对讲失败:" + errorMsg);
                    stopTalk();
                    callTalkListener(OnTalkListener.FAILED, errorMsg);
                    break;
                case EXCEPTION:
                    mTalking=false;
                    Logger.e(TAG, "onTalkStatus:取流异常:" + errorMsg);
                    stopTalk();
                    callTalkListener(OnTalkListener.EXCEPTION, errorMsg);
                    break;
            }
        }
    };

    /**
     * 录像回掉
     */
    private final PlayCallback.RecordCallback mRecordCallback = new PlayCallback.RecordCallback() {
        /**
         * 录像进度
         * @param time 单位毫秒
         */
        @Override
        public void recordTime(int time) {
            if (mVideoRecordListener != null) {
                ThreadUtils.runMainThread(() -> mVideoRecordListener.onRecordVideoTime(time));
            }
        }
    };


    private void initPlayer() {
        if (mPlayer != null) {
            Logger.d(TAG, "initPlayer:无需重复初始化播放器");
            return;
        }
        mPlayer = new DefaultHatomPlayer();
        //设置播放回掉
        mPlayer.setPlayStatusCallback(mPlayStatusCallback);
        //录像回掉
        mPlayer.setRecordCallback(mRecordCallback);
        //语音对讲回掉
        mPlayer.setVoiceStatusCallback(mVoiceTalkCallback);
    }


    /**
     * 开始播放
     */
    public void startPlay() {
        if (TextUtils.isEmpty(mPlayUrl)) {
            callError(PlayError.URL_IS_EMPTY, "playUrl为空");
            return;
        }
        if (mPlayer == null) {
            initPlayer();
            if (mPlayer == null) {
                callError(PlayError.PLAYER_INIT_FAILURE, "初始化播放器失败");
                return;
            }
        } else {
            if (mState != STATE_IDLE) {
                stopPlay();
            }
        }
        initPlayConfig();
        mPlayer.setPlayConfig(mPlayConfig);
        _setTextureView();
        mPlayer.setDataSource(mPlayUrl, mPlayHeaderMap);
        callStatusChange(STATE_START);
        enableAudio(!mMute);
        _start();
    }

    /**
     * 停止播放
     */
    public void stopPlay() {
        if (mState != STATE_IDLE) {
            _stop();
        }
        callStatusChange(STATE_IDLE);
    }

    /**
     * 暂停播放
     */
    public void pausePlay(){
        if (mState == STATE_PLAYING) {
            _pause();
        }
        callStatusChange(STATE_PAUSE);
    }

    /**
     * 恢复播放
     */
    public void resumePlay(){
        if (mState == STATE_PAUSE) {
            _resume();
        }
        callStatusChange(STATE_PLAYING);
    }

    /**
     * 开启对讲
     */
    public void startTalk() {
        if (mTalking) {
            Logger.d(TAG, "startVoiceTalk:正在对讲...");
            return;
        }
        if (TextUtils.isEmpty(mTalkUrl)) {
            callTalkListener(OnTalkListener.FAILED, "对讲url为空");
            return;
        }
        if (mPlayer == null) {
            initPlayer();
            if (mPlayer == null) {
                callTalkListener(OnTalkListener.FAILED, "初始化播放器失败");
                return;
            }
        }
        initPlayConfig();
        mPlayer.setPlayConfig(mPlayConfig);
        //设置对讲url和参数
        mPlayer.setVoiceDataSource(mTalkUrl, mTalkHeaderMap);
        enableAudio(true);
        callTalkListener(OnTalkListener.LOADING, null);
        _startVoiceTalk();
    }


    /**
     * 关闭对讲
     */
    public void stopTalk() {
        if (mTalking && mPlayer != null) {
            callTalkListener(OnTalkListener.CLOSE, null);
            mTalking = false;
            _stopVoiceTalk();
        }
    }

    /**
     * 设置播放url
     *
     * @param playUrl
     */
    public void setPlayUrl(String playUrl) {
        this.mPlayUrl = playUrl;
    }

    public void setTalkUrl(String talkUrl) {
        this.mTalkUrl = talkUrl;
    }

    /**
     * 设置播放/回放 header参数
     *
     * @param playHeaderMap
     */
    public void setPlayHeaderMap(Map<String, String> playHeaderMap) {
        this.mPlayHeaderMap = playHeaderMap;
    }
    /**
     * 设置对讲header参数
     *
     * @param talkHeaderMap
     */
    public void setTalkHeaderMap(Map<String, String> talkHeaderMap) {
        this.mTalkHeaderMap = talkHeaderMap;
    }


    /**
     * 设置预览显示
     *
     * @param textureView
     */
    public void setTextureView(TextureView textureView) {
        this.mTextureView = textureView;
        _setTextureView();
    }

    private void _setTextureView() {
        if (mPlayer != null && mTextureView != null && mTextureView.getSurfaceTexture() != null) {
            mPlayer.setSurfaceTexture(mTextureView.getSurfaceTexture());
        }
    }

    /**
     * 设置播放配置
     *
     * @param hikPlayConfig
     */
    public void setHikPlayConfig(HikPlayConfig hikPlayConfig) {
        this.mHikPlayConfig = hikPlayConfig;
    }

    /**
     * 播放监听
     *
     * @param playListener
     */
    public void setPlayListener(@Nullable OnPlayListener playListener) {
        this.mPlayListener = playListener;
    }

    /**
     * 设置截屏回掉
     *
     * @param capturePictureListener
     */
    public void setCapturePictureListener(@Nullable OnCapturePictureListener capturePictureListener) {
        this.mCapturePictureListener = capturePictureListener;
    }

    /**
     * 设置视频录制回掉
     *
     * @param videoRecordListener
     */
    public void setVideoRecordListener(@Nullable OnVideoRecordListener videoRecordListener) {
        this.mVideoRecordListener = videoRecordListener;
    }

    /**
     * 视频播放进度监听
     *
     * @param playProgressListener
     */
    public void setPlayProgressListener(@Nullable OnPlayProgressListener playProgressListener) {
        this.mPlayProgressListener = playProgressListener;
    }

    /**
     * 设置对讲监听
     *
     * @param onTalkListener
     */
    public void setOnTalkListener(OnTalkListener onTalkListener) {
        this.mOnTalkListener = onTalkListener;
    }

    /**
     * 使用{@link HikPlayConfig}初始化海康播放器配置
     */
    private void initPlayConfig() {
        if (mHikPlayConfig == null) {
            //使用硬解码
            mPlayConfig.hardDecode = true;
            //开启智能信息
            mPlayConfig.privateData = true;
        } else {
            mPlayConfig.fetchStreamType = mHikPlayConfig.fetchStreamType;
            mPlayConfig.hardDecode = mHikPlayConfig.hardDecode;
            mPlayConfig.privateData = mHikPlayConfig.privateData;
            mPlayConfig.timeout = mHikPlayConfig.timeout;
            mPlayConfig.secretKey = mHikPlayConfig.secretKey;
            mPlayConfig.playBuffer = mHikPlayConfig.playBuffer;
            mPlayConfig.useSysAEC = mHikPlayConfig.useSysAEC = true;
            mPlayConfig.ip = mHikPlayConfig.ip;
            mPlayConfig.port = mHikPlayConfig.port;
            mPlayConfig.username = mHikPlayConfig.username;
            mPlayConfig.password = mHikPlayConfig.password;
            mPlayConfig.qualityType = mHikPlayConfig.qualityType = 0;
            mPlayConfig.channelNum = mHikPlayConfig.channelNum;
            mPlayConfig.deviceSerial = mHikPlayConfig.deviceSerial;
            mPlayConfig.verifyCode = mHikPlayConfig.verifyCode;
            mPlayConfig.ttfPath = mHikPlayConfig.ttfPath;
        }
    }


    /**
     * 是否正在播放
     *
     * @return
     */
    public boolean isPlaying() {
        return mState == STATE_PLAYING;
    }

    /**
     * 是否暂停播放
     *
     * @return
     */
    public boolean isPause() {
        return mState == STATE_PAUSE;
    }

    /**
     * 是否正在对讲
     * @return
     */
    public boolean isTalking(){
        return mTalking;
    }

    /**
     * 是否是静音
     * @return
     */
    public boolean isMute() {
        return mMute;
    }

    /**
     * 获取播放状态
     *
     * @return
     */
    public @ZPlayer.State int getPlaySate() {
        return mState;
    }

    private void _start() {
        if (mPlayer != null) {
            new Thread(new Runnable() {
                @Override
                public void run() {
                    synchronized (this) {
                        if (mPlayer != null) {
                            mPlayer.start();
                        }
                    }
                }
            }).start();
        }
    }

    private void _playFile() {
        if (mPlayer != null) {
            new Thread(new Runnable() {
                @Override
                public void run() {
                    synchronized (this) {
                        if (mPlayer != null) {
                            mPlayer.playFile(mPlayUrl);
                        }
                    }
                }
            }).start();
        }
    }


    private void _stop() {
        if (mPlayer != null) {
            new Thread(new Runnable() {
                @Override
                public void run() {
                    synchronized (this) {
                        if (mPlayer != null) {
                            mPlayer.stop();
                        }
                    }
                }
            }).start();
        }
    }

    private void _resume() {
        if (mPlayer != null) {
            new Thread(new Runnable() {
                @Override
                public void run() {
                    synchronized (this) {
                        if (mPlayer != null) {
                            mPlayer.resume();
                        }
                    }
                }
            }).start();
        }
    }

    private void _pause() {
        if (mPlayer != null) {
            new Thread(new Runnable() {
                @Override
                public void run() {
                    synchronized (this) {
                        if (mPlayer != null) {
                            mPlayer.pause();
                        }
                    }
                }
            }).start();
        }
    }

    private void _startVoiceTalk() {
        if (mPlayer != null) {
            new Thread(new Runnable() {
                @Override
                public void run() {
                    synchronized (this) {
                        if (mPlayer != null) {
                            mPlayer.startVoiceTalk();
                        }
                    }
                }
            }).start();
        }
    }

    private void _stopVoiceTalk() {
        if (mPlayer != null) {
            new Thread(new Runnable() {
                @Override
                public void run() {
                    synchronized (this) {
                        if (mPlayer != null) {
                            mPlayer.stopVoiceTalk();
                        }
                    }
                }
            }).start();
        }
    }

    private void enableAudio(boolean enable){
        if(mPlayer!=null){
            int success = mPlayer.enableAudio(enable);
            if(success==HikErrors.SUCCESS){
                mMute=!enable;
            }
        }
    }
    /**
     * 播放状态改变时调用
     *
     * @param status
     */
    private void callStatusChange(@ZPlayer.State int status) {
        mState = status;
        if (mPlayListener != null) {
            ThreadUtils.runMainThread(() -> mPlayListener.onPlayStatusChange(status));
        }
    }

    /**
     * 播放错误时调用
     *
     * @param code
     * @param error
     */
    private void callError(@PlayError.ErrorCode int code, String error) {
        Log.e(TAG, String.format(Locale.CANADA, "callError:code:%d,error:%s", code, error));
        if (mPlayListener != null) {
            ThreadUtils.runMainThread(() -> mPlayListener.onPlayError(code, error));
        }
    }

    /**
     * 对讲监听调用
     */
    private void callTalkListener(int status, String error) {
        if (mOnTalkListener != null) {
            ThreadUtils.runMainThread(() -> mOnTalkListener.onTalkCallback(status, error));
        }
    }
}
